Intro

Goal: decide number of pops, maternal families, etc. Then planting design. Parameters: maximize number of pops, then number of maternal families. Plant 2000.

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.3.6      ✔ purrr   0.3.4 
✔ tibble  3.1.8      ✔ dplyr   1.0.10
✔ tidyr   1.2.0      ✔ stringr 1.4.1 
✔ readr   2.1.2      ✔ forcats 0.5.2 ── Conflicts ──────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(googlesheets4)
library(ggforce)

is.even <- function(x) x%%2 == 0

get data on pops and families

pops <- read_sheet("https://docs.google.com/spreadsheets/d/1dif9Y5hbkSa56Bgonj04-jXh8jNc6f13RBS6BPUf1IQ",
                   skip=1,
                   na=c("NA", ""),
                   col_types = c("ciiiccccc"),
                   .name_repair = "universal") %>%
  mutate(approx.number.seeds = as.integer(str_remove_all(approx.number.seeds,"[^0-9]")))
✔ Reading from Int Bio parents seed stock.
✔ Range 2:10000000.
New names:
pops

filter to one entry per pop, etc

pops.filtered <- pops %>% group_by(parent.pop) %>% slice_max(order_by=maternal.families) %>%
  filter(approx.number.seeds >= 100) %>%
  filter(!(parent.pop %in% c("HH", "RB"))) # old seed

pops.filtered %>% arrange(maternal.families)
sum(pops.filtered$maternal.families>=8)
[1] 21
sum(pops.filtered$maternal.families>=15)
[1] 18

Scenario 1:

Plant 21 pops * 8 families * 12 reps (= 2016 plants)

Scenario 2:

Plant 11 pops * 15 families * 12 reps (= 1980 plants)

Scenario 3:

__Note: after calculating above, Sarah found more mfs from WV, so:_

3 mfs from WR and 7 mfs from everyone else

total mfs = 3+722 = 157 13 reps (= 2041 plants)

planting grid

go with plan 3

2041 plants. 1 block per rep, so 13 blocks each of 157 plants

157/4 = 39.25 with 4 columns this is 39.25 plants per column per block. Call it 40

Create grid

blocks <- 13
columns <- 4
rows <- 40
plants <- blocks * columns * rows
size <- 20 # plant diameter
radius <- size/2 
aisle <- 90

plan3 <- expand_grid(block=LETTERS[1:blocks],
                     column=1:columns,
                     row=1:rows,
                     radius=radius)

plan3

add positions

column_offset <- sqrt((2*radius)^2 - radius^2) # Pythagorean theorem for offset spacing
plan3 <- plan3 %>%
  mutate(y_pos=ifelse(is.even(column),
                      row*size,
                      row*size-radius),
         x_pos=ifelse(column==1,
                      radius,
                      radius+(column-1)*column_offset))
plan3

Plot it

# only offset x_positions (1 "row" of blocks)
plan3 <- plan3 %>%
  mutate(block_x_offset = as.integer(as.factor(block))-1,
    block_x_offset = block_x_offset* (aisle + size + (columns-1)*column_offset))

#create block labels
block.labels <- plan3 %>%
  group_by(block) %>%
  summarize(x_pos = mean(x_pos+block_x_offset), y_pos=max(y_pos*1.075)) 


plan3 %>% #filter(block=="A", row <6) %>%
  ggplot(aes(x0=x_pos+block_x_offset, y0=y_pos, r=radius)) +
  geom_circle(fill="lightgreen", alpha=.25) + 
  coord_equal() + 
  geom_text(aes(x=x_pos, y=y_pos, label=block), size= 20, data = block.labels, inherit.aes = FALSE) + 
  theme(axis.text = element_text(size=16), axis.title = element_text(size=16)) +
  xlab("position (cm)") + ylab("position (cm)")

Alternate, what if we stack blocks

# only offset x_positions (1 "row" of blocks)
plan3 <- plan3 %>%
  mutate(block_x_offset = as.integer(as.factor(block)) %% 7 -1,
    block_x_offset = block_x_offset* (aisle + size + (columns-1)*column_offset)) %>%
  mutate(block_y_offset = (as.integer(as.factor(block)) %/% 7)*-1+1 ,
         block_y_offset = block_y_offset*size*rows+block_y_offset*aisle*1.5)

#create block labels
block.labels <- plan3 %>%
  group_by(block) %>%
  summarize(x_pos = mean(x_pos+block_x_offset), y_pos=max(block_y_offset + y_pos*1.075))


plan3 %>% #filter(block=="A", row <6) %>%
  ggplot(aes(x0=x_pos+block_x_offset, y0=y_pos+block_y_offset, r=radius)) +
  geom_circle(fill="lightgreen", alpha=.25) + 
  coord_equal() + 
  geom_text(aes(x=x_pos, y=y_pos, label=block), size= 20, data = block.labels, inherit.aes = FALSE) + 
  theme(axis.text = element_text(size=16), axis.title = element_text(size=16)) +
  xlab("position (cm)") + ylab("position (cm)")

LS0tCnRpdGxlOiAiQ29tbW9uIEdhcmRlbiBEZXNpZ24iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIEludHJvCgpHb2FsOiBkZWNpZGUgbnVtYmVyIG9mIHBvcHMsIG1hdGVybmFsIGZhbWlsaWVzLCBldGMuICBUaGVuIHBsYW50aW5nIGRlc2lnbi4KUGFyYW1ldGVyczogbWF4aW1pemUgbnVtYmVyIG9mIHBvcHMsIHRoZW4gbnVtYmVyIG9mIG1hdGVybmFsIGZhbWlsaWVzLiAgUGxhbnQgMjAwMC4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnb29nbGVzaGVldHM0KQpsaWJyYXJ5KGdnZm9yY2UpCgppcy5ldmVuIDwtIGZ1bmN0aW9uKHgpIHglJTIgPT0gMApgYGAKCiMjIGdldCBkYXRhIG9uIHBvcHMgYW5kIGZhbWlsaWVzCgpgYGB7cn0KcG9wcyA8LSByZWFkX3NoZWV0KCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xZGlmOVk1aGJrU2E1NkJnb25qMDQtalhoOGpOYzZmMTNSQlM2QlBVZjFJUSIsCiAgICAgICAgICAgICAgICAgICBza2lwPTEsCiAgICAgICAgICAgICAgICAgICBuYT1jKCJOQSIsICIiKSwKICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGMoImNpaWljY2NjYyIpLAogICAgICAgICAgICAgICAgICAgLm5hbWVfcmVwYWlyID0gInVuaXZlcnNhbCIpICU+JQogIG11dGF0ZShhcHByb3gubnVtYmVyLnNlZWRzID0gYXMuaW50ZWdlcihzdHJfcmVtb3ZlX2FsbChhcHByb3gubnVtYmVyLnNlZWRzLCJbXjAtOV0iKSkpCgpwb3BzCmBgYAojIyBmaWx0ZXIgdG8gb25lIGVudHJ5IHBlciBwb3AsIGV0YwoKYGBge3J9CnBvcHMuZmlsdGVyZWQgPC0gcG9wcyAlPiUgZ3JvdXBfYnkocGFyZW50LnBvcCkgJT4lIHNsaWNlX21heChvcmRlcl9ieT1tYXRlcm5hbC5mYW1pbGllcykgJT4lCiAgZmlsdGVyKGFwcHJveC5udW1iZXIuc2VlZHMgPj0gMTAwKSAlPiUKICBmaWx0ZXIoIShwYXJlbnQucG9wICVpbiUgYygiSEgiLCAiUkIiKSkpICMgb2xkIHNlZWQKCnBvcHMuZmlsdGVyZWQgJT4lIGFycmFuZ2UobWF0ZXJuYWwuZmFtaWxpZXMpCmBgYAoKYGBge3J9CnN1bShwb3BzLmZpbHRlcmVkJG1hdGVybmFsLmZhbWlsaWVzPj04KQpgYGAKCmBgYHtyfQpzdW0ocG9wcy5maWx0ZXJlZCRtYXRlcm5hbC5mYW1pbGllcz49MTUpCmBgYAoKIyMjIFNjZW5hcmlvIDE6CgpQbGFudCAyMSBwb3BzICogOCBmYW1pbGllcyAqIDEyIHJlcHMgKD0gMjAxNiBwbGFudHMpCgojIyMgU2NlbmFyaW8gMjoKClBsYW50IDExIHBvcHMgKiAxNSBmYW1pbGllcyAqIDEyIHJlcHMgKD0gMTk4MCBwbGFudHMpCgojIyMgU2NlbmFyaW8gMzoKCl9fTm90ZTogYWZ0ZXIgY2FsY3VsYXRpbmcgYWJvdmUsIFNhcmFoIGZvdW5kIG1vcmUgbWZzIGZyb20gV1YsIHNvOl8KCjMgbWZzIGZyb20gV1IgYW5kIDcgbWZzIGZyb20gZXZlcnlvbmUgZWxzZQoKdG90YWwgbWZzID0gMys3KjIyID0gMTU3ICogMTMgcmVwcyAoPSAyMDQxIHBsYW50cykKCiMjIHBsYW50aW5nIGdyaWQKCiMjIyBnbyB3aXRoIHBsYW4gMwoKMjA0MSBwbGFudHMuICAxIGJsb2NrIHBlciByZXAsIHNvIDEzIGJsb2NrcyBlYWNoIG9mIDE1NyBwbGFudHMKCjE1Ny80ID0gMzkuMjUgd2l0aCA0IGNvbHVtbnMgdGhpcyBpcyAzOS4yNSBwbGFudHMgcGVyIGNvbHVtbiBwZXIgYmxvY2suICBDYWxsIGl0IDQwCgpDcmVhdGUgZ3JpZApgYGB7cn0KYmxvY2tzIDwtIDEzCmNvbHVtbnMgPC0gNApyb3dzIDwtIDQwCnBsYW50cyA8LSBibG9ja3MgKiBjb2x1bW5zICogcm93cwpzaXplIDwtIDIwICMgcGxhbnQgZGlhbWV0ZXIKcmFkaXVzIDwtIHNpemUvMiAKYWlzbGUgPC0gOTAKCnBsYW4zIDwtIGV4cGFuZF9ncmlkKGJsb2NrPUxFVFRFUlNbMTpibG9ja3NdLAogICAgICAgICAgICAgICAgICAgICBjb2x1bW49MTpjb2x1bW5zLAogICAgICAgICAgICAgICAgICAgICByb3c9MTpyb3dzLAogICAgICAgICAgICAgICAgICAgICByYWRpdXM9cmFkaXVzKQoKcGxhbjMKYGBgCgphZGQgcG9zaXRpb25zCmBgYHtyfQpjb2x1bW5fb2Zmc2V0IDwtIHNxcnQoKDIqcmFkaXVzKV4yIC0gcmFkaXVzXjIpICMgUHl0aGFnb3JlYW4gdGhlb3JlbSBmb3Igb2Zmc2V0IHNwYWNpbmcKcGxhbjMgPC0gcGxhbjMgJT4lCiAgbXV0YXRlKHlfcG9zPWlmZWxzZShpcy5ldmVuKGNvbHVtbiksCiAgICAgICAgICAgICAgICAgICAgICByb3cqc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgIHJvdypzaXplLXJhZGl1cyksCiAgICAgICAgIHhfcG9zPWlmZWxzZShjb2x1bW49PTEsCiAgICAgICAgICAgICAgICAgICAgICByYWRpdXMsCiAgICAgICAgICAgICAgICAgICAgICByYWRpdXMrKGNvbHVtbi0xKSpjb2x1bW5fb2Zmc2V0KSkKcGxhbjMKYGBgClBsb3QgaXQKYGBge3IsIGZpZy53aWR0aD0xMn0KIyBvbmx5IG9mZnNldCB4X3Bvc2l0aW9ucyAoMSAicm93IiBvZiBibG9ja3MpCnBsYW4zIDwtIHBsYW4zICU+JQogIG11dGF0ZShibG9ja194X29mZnNldCA9IGFzLmludGVnZXIoYXMuZmFjdG9yKGJsb2NrKSktMSwKICAgIGJsb2NrX3hfb2Zmc2V0ID0gYmxvY2tfeF9vZmZzZXQqIChhaXNsZSArIHNpemUgKyAoY29sdW1ucy0xKSpjb2x1bW5fb2Zmc2V0KSkKCiNjcmVhdGUgYmxvY2sgbGFiZWxzCmJsb2NrLmxhYmVscyA8LSBwbGFuMyAlPiUKICBncm91cF9ieShibG9jaykgJT4lCiAgc3VtbWFyaXplKHhfcG9zID0gbWVhbih4X3BvcytibG9ja194X29mZnNldCksIHlfcG9zPW1heCh5X3BvcyoxLjA3NSkpIAoKCnBsYW4zICU+JSAjZmlsdGVyKGJsb2NrPT0iQSIsIHJvdyA8NikgJT4lCiAgZ2dwbG90KGFlcyh4MD14X3BvcytibG9ja194X29mZnNldCwgeTA9eV9wb3MsIHI9cmFkaXVzKSkgKwogIGdlb21fY2lyY2xlKGZpbGw9ImxpZ2h0Z3JlZW4iLCBhbHBoYT0uMjUpICsgCiAgY29vcmRfZXF1YWwoKSArIAogIGdlb21fdGV4dChhZXMoeD14X3BvcywgeT15X3BvcywgbGFiZWw9YmxvY2spLCBzaXplPSAyMCwgZGF0YSA9IGJsb2NrLmxhYmVscywgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKyAKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNikpICsKICB4bGFiKCJwb3NpdGlvbiAoY20pIikgKyB5bGFiKCJwb3NpdGlvbiAoY20pIikKYGBgCgpBbHRlcm5hdGUsIHdoYXQgaWYgd2Ugc3RhY2sgYmxvY2tzCgpgYGB7ciwgZmlnLndpZHRoPTEyfQojIG9ubHkgb2Zmc2V0IHhfcG9zaXRpb25zICgxICJyb3ciIG9mIGJsb2NrcykKcGxhbjMgPC0gcGxhbjMgJT4lCiAgbXV0YXRlKGJsb2NrX3hfb2Zmc2V0ID0gYXMuaW50ZWdlcihhcy5mYWN0b3IoYmxvY2spKSAlJSA3IC0xLAogICAgYmxvY2tfeF9vZmZzZXQgPSBibG9ja194X29mZnNldCogKGFpc2xlICsgc2l6ZSArIChjb2x1bW5zLTEpKmNvbHVtbl9vZmZzZXQpKSAlPiUKICBtdXRhdGUoYmxvY2tfeV9vZmZzZXQgPSAoYXMuaW50ZWdlcihhcy5mYWN0b3IoYmxvY2spKSAlLyUgNykqLTErMSAsCiAgICAgICAgIGJsb2NrX3lfb2Zmc2V0ID0gYmxvY2tfeV9vZmZzZXQqc2l6ZSpyb3dzK2Jsb2NrX3lfb2Zmc2V0KmFpc2xlKjEuNSkKCiNjcmVhdGUgYmxvY2sgbGFiZWxzCmJsb2NrLmxhYmVscyA8LSBwbGFuMyAlPiUKICBncm91cF9ieShibG9jaykgJT4lCiAgc3VtbWFyaXplKHhfcG9zID0gbWVhbih4X3BvcytibG9ja194X29mZnNldCksIHlfcG9zPW1heChibG9ja195X29mZnNldCArIHlfcG9zKjEuMDc1KSkKCgpwbGFuMyAlPiUgI2ZpbHRlcihibG9jaz09IkEiLCByb3cgPDYpICU+JQogIGdncGxvdChhZXMoeDA9eF9wb3MrYmxvY2tfeF9vZmZzZXQsIHkwPXlfcG9zK2Jsb2NrX3lfb2Zmc2V0LCByPXJhZGl1cykpICsKICBnZW9tX2NpcmNsZShmaWxsPSJsaWdodGdyZWVuIiwgYWxwaGE9LjI1KSArIAogIGNvb3JkX2VxdWFsKCkgKyAKICBnZW9tX3RleHQoYWVzKHg9eF9wb3MsIHk9eV9wb3MsIGxhYmVsPWJsb2NrKSwgc2l6ZT0gMjAsIGRhdGEgPSBibG9jay5sYWJlbHMsIGluaGVyaXQuYWVzID0gRkFMU0UpICsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTYpKSArCiAgeGxhYigicG9zaXRpb24gKGNtKSIpICsgeWxhYigicG9zaXRpb24gKGNtKSIpCmBgYAoKYGBge3J9CnBsYW50cyAgPC0gcmVhZF9zaGVldCgiICBodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xRWFTQTJRcmxXQWpGUjM1cGVkY3ZoZVFwM1g3QWdzbGE2cFp0RTJDMVFKNCIsCiAgICAgICAgICAgICAgICAgICAgICBzaGVldD0ibGFiZWwgbWFraW5nIikKCnBsYW50cyAKIiwKICAgICAgICAgICAgICAgICAgIHNraXA9MSwKICAgICAgICAgICAgICAgICAgIG5hPWMoIk5BIiwgIiIpLAogICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gYygiY2lpaWNjY2NjIiksCiAgICAgICAgICAgICAgICAgICAubmFtZV9yZXBhaXIgPSAidW5pdmVyc2FsIikgJT4lCiAgbXV0YXRlKGFwcHJveC5udW1iZXIuc2VlZHMgPSBhcy5pbnRlZ2VyKHN0cl9yZW1vdmVfYWxsKGFwcHJveC5udW1iZXIuc2VlZHMsIlteMC05XSIpKSkKCnBvcHMKICAKYGBgCgo=